package czk.page.renderer;

import java.io.Writer;
import java.io.IOException;

import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.sys.PageCtrl;
import org.zkoss.zk.ui.sys.ComponentCtrl;
import org.zkoss.zk.ui.sys.ExecutionsCtrl;
import org.zkoss.zk.ui.sys.HtmlPageRenders;

public class CZKPageRenderer implements org.zkoss.zk.ui.sys.PageRenderer {
	public void render(Page page, Writer out) throws IOException {
		final Execution exec = Executions.getCurrent();
		final String ctl = ExecutionsCtrl.getPageRedrawControl(exec);
		boolean au = exec.isAsyncUpdate(null);
		if (!au && (page.isComplete() || "complete".equals(ctl))) {
			renderComplete(exec, page, out);
			return;
		}

		boolean pageOnly = au;
		if (!pageOnly)
			pageOnly = (exec.isIncluded() || "page".equals(ctl))
					&& !"desktop".equals(ctl);

		if (pageOnly)
			renderPage(exec, page, out, au);
		else
			renderDesktop(exec, page, out);
	}

	/**
	 * Renders the desktop and the page.
	 */
	protected void renderDesktop(Execution exec, Page page, Writer out)
			throws IOException {
		HtmlPageRenders.setContentType(exec, page);

		final PageCtrl pageCtrl = (PageCtrl) page;
		write(out, HtmlPageRenders.outFirstLine(exec, page)); // might null
		write(out, HtmlPageRenders.outDocType(exec, page)); // might null
		out.write("<html xmlns=\"http://www.w3.org/1999/xhtml\"");
		write(out, pageCtrl.getRootAttributes());
		out.write(">\n<head>\n"
				+ "<meta http-equiv=\"Pragma\" content=\"no-cache\" />\n"
				+ "<meta http-equiv=\"Expires\" content=\"-1\" />\n"
				+ "<title>");
		write(out, page.getTitle());
		out.write("</title>\n");
		outHeaders(exec, page, out);
		out.write("</head>\n");

		out.write("<body>\n");

		HtmlPageRenders.outPageContent(exec, page, out, false);
		writeln(out, HtmlPageRenders.outUnavailable(exec));
		out.write("\n</body>\n</html>\n");
	}

	private static void outHeaders(Execution exec, Page page, Writer out)
			throws IOException {
		out.write(HtmlPageRenders.outHeaders(exec, page, true));

		out.write("<script src=\"./closure-library/closure/goog/base.js\"></script>");
		out.write("<script src=\"./closure/czk/deps.js\"></script>");
		out.write("<script >goog.require('czk.initczk');</script>");
		
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/common.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/flatmenubutton.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/menubutton.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/menu.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/menuitem.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/menuseparator.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/toolbar.css\">");
		
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/datepicker.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/inputdatepicker.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/dialog.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/button.css\">");
		out.write("<link rel=\"stylesheet\" href=\"./closure-library/closure/goog/css/combobox.css\">");
		
		// out.write(HtmlPageRenders.outLangStyleSheets(exec, null, null));
		// out.write(HtmlPageRenders.outLangJavaScripts(exec, null, null));
		out.write(HtmlPageRenders.outHeaders(exec, page, false));

	}

	private static void write(Writer out, String s) throws IOException {
		if (s != null)
			out.write(s);
	}

	private static void writeln(Writer out, String s) throws IOException {
		if (s != null) {
			out.write(s);
			out.write('\n');
		}
	}

	/**
	 * Renders the page if {@link Page#isComplete} is false.
	 * 
	 * @param au
	 *            whether it is caued by an asynchronous update
	 */
	protected void renderPage(Execution exec, Page page, Writer out, boolean au)
			throws IOException {
		if (!au) {
			out.write(HtmlPageRenders.outLangStyleSheets(exec, null, null));
			out.write(HtmlPageRenders.outLangJavaScripts(exec, null, null));
		}

		HtmlPageRenders.outPageContent(exec, page, out, au);
		if (!au && ((PageCtrl) page).getOwner() == null)
			writeln(out, HtmlPageRenders.outUnavailable(exec));
	}

	/**
	 * Renders the page if {@link Page#isComplete} is true. In other words, the
	 * page content contains HTML/BODY tags.
	 */
	protected void renderComplete(Execution exec, Page page, Writer out)
			throws IOException {
		write(out, HtmlPageRenders.outFirstLine(exec, page)); // might null
		write(out, HtmlPageRenders.outDocType(exec, page)); // might null
		HtmlPageRenders.setContentType(exec, page);

		for (Component root = page.getFirstRoot(); root != null; root = root
				.getNextSibling())
			((ComponentCtrl) root).redraw(out);

		write(out, HtmlPageRenders.outHeaderZkTags(exec, page));
		writeln(out, HtmlPageRenders.outUnavailable(exec));
	}
}
